package com.cskaoyan.duolai.clean.housekeeping.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cskaoyan.duolai.clean.common.expcetions.ForbiddenOperationException;
import com.cskaoyan.duolai.clean.common.model.dto.PageDTO;
import com.cskaoyan.duolai.clean.housekeeping.converter.RegionConverter;
import com.cskaoyan.duolai.clean.housekeeping.converter.RegionServeConverter;
import com.cskaoyan.duolai.clean.housekeeping.dao.entity.CityDirectoryDO;
import com.cskaoyan.duolai.clean.housekeeping.dao.entity.RegionDO;
import com.cskaoyan.duolai.clean.housekeeping.dao.entity.RegionServeDO;
import com.cskaoyan.duolai.clean.housekeeping.dao.entity.RegionServeDetailDO;
import com.cskaoyan.duolai.clean.housekeeping.dao.mapper.CityDirectoryMapper;
import com.cskaoyan.duolai.clean.housekeeping.dao.mapper.RegionMapper;
import com.cskaoyan.duolai.clean.housekeeping.dao.mapper.RegionServeMapper;
import com.cskaoyan.duolai.clean.housekeeping.dto.RegionDTO;
import com.cskaoyan.duolai.clean.housekeeping.dto.RegionServeDetailDTO;
import com.cskaoyan.duolai.clean.housekeeping.dto.RegionSimpleDTO;
import com.cskaoyan.duolai.clean.housekeeping.enums.HousekeepingStatusEnum;
import com.cskaoyan.duolai.clean.housekeeping.request.RegionCommand;
import com.cskaoyan.duolai.clean.housekeeping.request.RegionPageRequest;
import com.cskaoyan.duolai.clean.housekeeping.service.IConfigRegionService;
import com.cskaoyan.duolai.clean.housekeeping.service.IRegionServeService;
import com.cskaoyan.duolai.clean.housekeeping.service.IRegionService;
import com.cskaoyan.duolai.clean.mysql.utils.PageUtils;
import com.cskaoyan.duolai.clean.redis.constants.RedisConstants;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 区域管理
 **/
@Service
public class RegionServiceImpl extends ServiceImpl<RegionMapper, RegionDO> implements IRegionService {
    @Resource
    private IConfigRegionService configRegionService;
    @Resource
    private CityDirectoryMapper cityDirectoryMapper;

    @Resource
    RegionConverter regionConverter;

    @Resource
    IRegionServeService regionServeService;

    @Resource
    IRegionService regionService;
    @Resource
    RegionServeMapper regionServeMapper;
    @Resource
    RedissonClient redissonClient;
    @Resource
    RegionServeConverter regionServeConverter;



    /**
     * 区域新增
     *
     * @param regionCommand 插入更新区域
     */
    @Override
    @Transactional

    public void addRegion(RegionCommand regionCommand) {
        //1.校验城市编码是否重复
        String cityCode = regionCommand.getCityCode();
        LambdaQueryWrapper<RegionDO> regionQueryWrapper = Wrappers.<RegionDO>lambdaQuery().eq(RegionDO::getCityCode, cityCode);
        Long count = baseMapper.selectCount(regionQueryWrapper);
        if(count>0){
            throw new ForbiddenOperationException("城市编码不可重复");
        }
        //查询城市
        LambdaQueryWrapper<CityDirectoryDO> cityQueryWrapper = Wrappers.<CityDirectoryDO>lambdaQuery().eq(CityDirectoryDO::getCityCode, cityCode);
        CityDirectoryDO cityDirectoryDO = cityDirectoryMapper.selectOne(cityQueryWrapper);
        if (ObjectUtil.isNull(cityDirectoryDO)){
            throw new ForbiddenOperationException("该城市还未开通服务");
        }
        //查询城市的排序位
        Integer sortNum = cityDirectoryDO.getSortNum();
        //2.新增区域
        RegionDO regionDO = regionConverter.regionCommandToRegionDO(regionCommand);
        regionDO.setSortNum(sortNum);
        baseMapper.insert(regionDO);
        //3.初始化区域配置
        configRegionService.init(regionDO.getId(), regionDO.getCityCode());
    }

    /**
     * 区域修改
     *
     * @param id           区域id
     * @param managerName  负责人姓名
     * @param managerPhone 负责人电话
     */
    @Override
    public void update(Long id, String managerName, String managerPhone) {
        RegionDO oldRegion = baseMapper.selectById(id);
        if (HousekeepingStatusEnum.INIT.getStatus() != oldRegion.getActiveStatus()) {
            throw new ForbiddenOperationException("草稿状态方可修改");
        }

        oldRegion.setManagerName(managerName);
        oldRegion.setManagerPhone(managerPhone);
        baseMapper.updateById(oldRegion);
    }

    /**
     * 区域删除
     *
     * @param id 区域id
     */
    @Override
    @Transactional
    public void deleteById(Long id) {
        //区域信息
        RegionDO regionDO = baseMapper.selectById(id);
        if (ObjectUtil.isNull(regionDO)){
            throw new ForbiddenOperationException("区域类型不存在");
        }
        //草稿状态方可删除
        if (HousekeepingStatusEnum.INIT.getStatus() != regionDO.getActiveStatus()) {
            throw new ForbiddenOperationException("草稿状态方可删除");
        }
        //删除

        baseMapper.deleteById(id);
    }

    /**
     * 分页查询
     *
     * @param regionPageQueryReqDTO 查询条件
     * @return 分页结果
     */
    @Override
    public PageDTO<RegionDTO> getPage(RegionPageRequest regionPageQueryReqDTO) {

        Page<RegionDO> page = PageUtils.parsePageQuery(regionPageQueryReqDTO, RegionDO.class);
        Page<RegionDO> regionDOPage = baseMapper.selectPage(page, new QueryWrapper<>());
        List<RegionDTO> regionDTOS = regionConverter.regionDOsToRegionDTOs(regionDOPage.getRecords());

        return PageUtils.toPage(page, regionDTOS);
    }

    /**
     * 已开通服务区域列表
     *
     * @return 区域列表
     */
    @Override
    public List<RegionSimpleDTO> queryActiveRegionListDb() {
        System.out.println("queryActiveRegionListDb  " );
        QueryWrapper<RegionServeDO> regionServeWrapper = new QueryWrapper<>();
        regionServeWrapper.select("city_code");
        Set<String> regionCityCodeSet = regionServeMapper.selectList(regionServeWrapper)
                .stream().map(RegionServeDO::getCityCode).collect(Collectors.toSet());
        List<RegionDO> regionDOList = new ArrayList<>();
        for (String cityCode : regionCityCodeSet) {
            LambdaQueryWrapper<RegionDO> regionDOWrapper = new LambdaQueryWrapper<>();
            regionDOWrapper.eq(RegionDO::getCityCode, cityCode);
            RegionDO one = regionService.getOne(regionDOWrapper);
            regionDOList.add(one);
        }
        return regionConverter.regionDOsToRegionSimpleDTOs(regionDOList);
    }

    /**
     * 区域启用
     *
     * @param id 区域id
     */
    @Override
    @CachePut(cacheNames = RedisConstants.CacheName.REGION_CACHE, key = "'ACTIVE_REGIONS'")
    public List<RegionSimpleDTO> active(Long id) {
        //区域信息
        RegionDO regionDO = baseMapper.selectById(id);
        if (ObjectUtil.isNull(regionDO)) {
            throw new ForbiddenOperationException("区域类型不存在");
        }
        //草稿或禁用状态方可启用
        Integer activeStatus = regionDO.getActiveStatus();
        //草稿或禁用状态方可启用
        if (!(HousekeepingStatusEnum.INIT.getStatus() == activeStatus || HousekeepingStatusEnum.DISABLE.getStatus() == activeStatus)) {
            throw new ForbiddenOperationException("草稿或禁用状态方可启用");
        }

        //更新启用状态
        LambdaUpdateWrapper<RegionDO> updateWrapper = Wrappers.<RegionDO>lambdaUpdate()
                .eq(RegionDO::getId, id)
                .set(RegionDO::getActiveStatus, HousekeepingStatusEnum.ENABLE.getStatus());
        update(updateWrapper);
        return queryActiveRegionListDb();
    }

    /**
     * 区域禁用
     *
     * @param id 区域id
     */
    @Override
    @CachePut(cacheNames = RedisConstants.CacheName.REGION_CACHE, key = "'ACTIVE_REGIONS'")
    public List<RegionSimpleDTO> deactivate(Long id) {
        //区域信息
        RegionDO regionDO = baseMapper.selectById(id);
        if (ObjectUtil.isNull(regionDO)) {
            throw new ForbiddenOperationException("区域类型不存在");
        }
        //启用状态
        Integer activeStatus = regionDO.getActiveStatus();
        //启用状态方可禁用
        if (!(HousekeepingStatusEnum.ENABLE.getStatus() == activeStatus)) {
            throw new ForbiddenOperationException("启用状态方可禁用");
        }

        //如果禁用区域下有上架的服务则无法禁用
        int saleCount = regionServeService.queryServeCountByRegionIdAndSaleStatus(id, HousekeepingStatusEnum.ENABLE.getStatus());
        if (saleCount > 0){
            throw new ForbiddenOperationException("尚有区域正在使用服务" + regionDO.getName());
        }
        //更新禁用状态
        LambdaUpdateWrapper<RegionDO> updateWrapper = Wrappers.<RegionDO>lambdaUpdate().eq(RegionDO::getId, id).set(RegionDO::getActiveStatus, HousekeepingStatusEnum.DISABLE.getStatus());
        update(updateWrapper);
        return queryActiveRegionListDb();
    }

    /**
     * 已开通服务区域列表
     *
     * @return 区域简略列表
     */
    @Override
    @Cacheable(cacheNames = RedisConstants.CacheName.REGION_CACHE, key = "'ACTIVE_REGIONS'")
    public List<RegionSimpleDTO> queryActiveRegionListCache() {
       return queryActiveRegionListDb();
    }


    @Autowired
    RegionServeConverter converter;
    /**
     * 刷新区域id相关缓存：首页图标、热门服务、服务分类
     *
     * @param regionId 区域id
     */
    @Override
    public void refreshRegionRelateCaches(Long regionId) {
        //刷新首页区域服务列表缓存
         regionServeService.refreshFirstPageRegionServeList(regionId);
         //刷新服务类型缓存
         regionServeService.refreshFirstPageServeTypeList(regionId);
         //刷新热门服务缓存
         regionServeService.refreshFistPageHotServeList(regionId);

        List<RegionServeDetailDO> dbRegionServerlist = regionServeMapper.findRegionServeDetailByRegionId(regionId);
        List<Long> dbRegionServeridList = dbRegionServerlist.stream().map(RegionServeDetailDO::getId).toList();
        RMap<Long, RegionServeDetailDTO> cacheRegionServeMap = redissonClient.getMap(RedisConstants.CacheName.REGION_SERVE_DETAIL);

        Map<Long, RegionServeDetailDTO> collect = cacheRegionServeMap.entrySet().stream().filter((entry) -> {
            RegionServeDetailDTO value = entry.getValue();
            return value.getRegionId().equals(regionId);
        }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));


        List<Long> deleteidlist = collect.keySet().stream().filter((cacheid) -> {
            return !dbRegionServeridList.contains(cacheid);
        }).toList();

        deleteidlist.forEach(id -> {
            cacheRegionServeMap.remove(id);
        });
        dbRegionServerlist.forEach(regionServeDetailDO -> {
            RegionServeDetailDTO regionServeDetailDTO
                    = regionServeConverter.regionServeDetailDO2DTO(regionServeDetailDO);
            cacheRegionServeMap.put(regionServeDetailDTO.getId(), regionServeDetailDTO);
        });











    }

}
